﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AAA.Meta.Chart.Data
{
    public class Profile
    {
        public const string CHART_LABEL = "ABCDEFGHIJKLMNPQRSTUVWXYabcdefghijklmnopqrstuvwxyz";
        private DateTime _baseTime;
        private DateTime _endTime;
        private int _iTimePeriod = 15 * 60;
        private float _fPriceInterval;
        private List<float> _lstPrice;
        private Dictionary<float, List<string>> _dicCharProfile;
        private Dictionary<float, List<int>> _dicVolumeProfile;
        private Dictionary<float, List<int>> _dicTickProfile;
        private float _fDayHighest;
        private float _fDayLowest;
        private float _fDayOpen;
        private float _fDayClose;
        private int _iDayVolume;
        private int _iDayTicks;
        private int _iTotalTPOCount;
        private float _fPOCPrice;
        private int _iPOCTPOCount;
        private bool _needRecalculate;

        public Profile()
        {
            _baseTime = DateTime.Parse(DateTime.Now.ToString("yyyy/MM/dd") + " 08:45:00");
            _lstPrice = new List<float>();
            _dicCharProfile = new Dictionary<float, List<string>>();
            _dicVolumeProfile = new Dictionary<float, List<int>>();
            _dicTickProfile = new Dictionary<float, List<int>>();
            _fDayHighest = -float.MaxValue;
            _fDayLowest = float.MaxValue;
            _fDayClose = float.NaN;
            _fDayOpen = float.NaN;
            _iDayVolume = 0;
            _iDayTicks = 0;
            _needRecalculate = true;
        }

        public float DayHighest
        {
            get { return _fDayHighest; }
            set { _fDayHighest = value; }
        }

        public float DayLowest
        {
            get { return _fDayLowest; }
            set { _fDayLowest = value; }
        }

        public float DayOpen
        {
            get { return _fDayOpen; }
            set { _fDayOpen = value; }
        }

        public float DayClose
        {
            get { return _fDayClose; }
            set { _fDayClose = value; }
        }

        public int DayVolume
        {
            get { return _iDayVolume; }
            set { _iDayVolume = value; }
        }

        public int DayTicks
        {
            get { return _iDayTicks; }
            set { _iDayTicks = value; }
        }

        public int TotalTPOCount
        {
            get 
            {
//                CalculateTPO();
                return _iTotalTPOCount; 
            }
            set { _iTotalTPOCount = value; }
        }

        public float POCPrice
        {
            get 
            {
//                CalculateTPO();
                return _fPOCPrice; 
            }
            set { _fPOCPrice = value; }
        }

        public int POCTPOCount
        {
            get 
            {
//                CalculateTPO();
                return _iPOCTPOCount; 
            }
            set { _iPOCTPOCount = value; }
        }

        public DateTime BaseTime
        {
            get { return _baseTime; }
            set { _baseTime = value; }
        }

        public DateTime EndTime
        {
            get { return _endTime; }
            set { _endTime = value; }
        }

        public float PriceInterval
        {
            get { return _fPriceInterval; }
            set { _fPriceInterval = value; }
        }

        public int TimePeriod
        {
            get { return _iTimePeriod; }
            set { _iTimePeriod = value; }
        }

        public List<float> PriceList
        {
            get { return _lstPrice; }
        }

        public List<string> TPOList(float fPrice)
        {
            return _dicCharProfile.ContainsKey(fPrice)
                    ? _dicCharProfile[fPrice]
                    : null;
        }

        public float VolumeAtPrice(float fPrice)
        {
            return _dicVolumeProfile.ContainsKey(fPrice)
                    ? _dicVolumeProfile[fPrice][0]
                    : 0;
        }

        public float TickAtPrice(float fPrice)
        {
            return _dicTickProfile.ContainsKey(fPrice)
                    ? _dicTickProfile[fPrice][0]
                    : 0;
        }

        public bool IsPeriodOpen(DateTime dtTime)
        {
            TimeSpan timeSpan = new TimeSpan(dtTime.Ticks - BaseTime.Ticks);
            return ((timeSpan.TotalSeconds % TimePeriod) == 60);
        }

        public void CalculateTPO()
        {
            if (_needRecalculate == false)
                return;

            _iTotalTPOCount = 0;
            _iPOCTPOCount = 0;
            float[] fPrice;

            for (int i = 0; i < _lstPrice.Count; i++)
            {
                if (_dicCharProfile[_lstPrice[i]].Count > POCTPOCount)
                {
                    POCTPOCount = _dicCharProfile[_lstPrice[i]].Count;
                    POCPrice = _lstPrice[i];
                }
                TotalTPOCount += _dicCharProfile[_lstPrice[i]].Count;
            }

            fPrice = _lstPrice.ToArray();
            Array.Sort(fPrice);
            while (_lstPrice.Count > 0)
                _lstPrice.RemoveAt(0);

            for (int i = 0; i < fPrice.Length; i++)
                _lstPrice.Add(fPrice[i]);

            _needRecalculate = false;
        }

        public float PriceLabel(float fPrice)
        {
            return (float)(Math.Floor(fPrice / PriceInterval) * PriceInterval);
        }

        public string CurrentChar(DateTime dtTime)
        {
            try
            {
                if (dtTime.Ticks >= EndTime.Ticks)
                    dtTime = EndTime;

                TimeSpan timeSpan = new TimeSpan(dtTime.Ticks - BaseTime.Ticks);
                return CHART_LABEL.Substring(((int)Math.Floor(((double)timeSpan.TotalSeconds / (double)TimePeriod))) % CHART_LABEL.Length, 1);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }
            return null;
        }

        public void AddData(DateTime dtTime, float fPrice, int iVolume)
        {
            AddData(dtTime, fPrice, iVolume, 1);
        }

        public void AddData(DateTime dtTime, float fPrice, int iVolume, int iTick)
        {
            List<string> lstChar;
            List<int> lstVol;
            string strCurrentChar = null;
            float fPriceLabel;

            try
            {
                DayHighest = Math.Max(fPrice, DayHighest);
                DayLowest = Math.Min(fPrice, DayLowest);
                DayVolume += iVolume;
                DayTicks += iTick;

                //fPriceLabel = (float)(Math.Floor(fPrice / PriceInterval) * PriceInterval);
                fPriceLabel = PriceLabel(fPrice);
                strCurrentChar = CurrentChar(dtTime);

                if (_lstPrice.IndexOf(fPriceLabel) < 0)
                {
                    _lstPrice.Add(fPriceLabel);
                    _dicCharProfile.Add(fPriceLabel, new List<string>());
                    _dicVolumeProfile.Add(fPriceLabel, new List<int>());
                    _dicTickProfile.Add(fPriceLabel, new List<int>());
                }

                lstChar = _dicCharProfile[fPriceLabel];
                if (lstChar.IndexOf(strCurrentChar) < 0)
                    lstChar.Add(strCurrentChar);

                lstVol = _dicVolumeProfile[fPriceLabel];
                if (lstVol.Count == 0)
                    lstVol.Add(0);
                lstVol[0] += iVolume;

                lstVol = _dicTickProfile[fPriceLabel];
                if (lstVol.Count == 0)
                    lstVol.Add(0);
                lstVol[0] += iTick;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }
            _needRecalculate = true;
        }
    }
}
